package com.wontube.smr.bo.pub;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Calendar;

import javax.servlet.AsyncContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.ibatis.session.SqlSession;

import com.wontube.client.extension.utils.FileUtils;
import com.wontube.client.extension.utils.StringUtils;
import com.wontube.client.extension.utils.net.URLUtils;
import com.wontube.core.pub.AppEnvironment;
import com.wontube.smr.client.model.po.Mp3Url;
import com.wontube.smr.client.model.po.VideoPage;
import com.wontube.smr.dao.mapper.Mp3UrlMapper;
import com.wontube.smr.pub.DefaultDBHelper;




/**
 * @author yuechao
 *
 */
public final class Mp3DownloadListenter implements Runnable {
	private AsyncContext ac;
	private VideoPage page;
	private Mp3Url mp3Url;

	public Mp3DownloadListenter(AsyncContext ac, VideoPage page, Mp3Url mp3Url) {
		this.ac = ac;
		this.page = page;
		this.mp3Url = mp3Url;
	}

	/*
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		try {
			if (this.download()) {
				// 下载计数
				SqlSession session = DefaultDBHelper.getSqlSession(false);

				try {
					Mp3UrlMapper mapper = session.getMapper(Mp3UrlMapper.class);
					Mp3Url mp3Url = mapper.selectByPrimaryKey(this.mp3Url.getId());
					if (mp3Url != null) {
						int downTimes = mp3Url.getDownTimes() + 1;
						mp3Url.setDownTimes(downTimes);
						mp3Url.setVersion(Calendar.getInstance().getTime());
						mapper.updateByPrimaryKey(mp3Url);
					}
					session.commit();
				} finally {
					session.close();
				}
			}
		} catch (IOException e) {
			// 用户取消
		} finally {
			this.ac.complete();
		}
	}

	// 返回是否下载完成
	private boolean download() throws IOException {
		String relativePath = StringUtils.format("mp3{}{}{}{}{}{}.{}",
				File.separator, 
				page.getSiteName(),
				File.separator, 
				this.mp3Url.getPath(), 
				File.separator, 
				this.mp3Url.getId(), 
				mp3Url.getAudioFormat());
		String path = FileUtils.combinePath(AppEnvironment.dataPath, relativePath);

		File file = new File(path);
		if (!file.exists()) {
			return false;
		}

		HttpServletRequest req = (HttpServletRequest) this.ac.getRequest();
		HttpServletResponse resp = (HttpServletResponse) this.ac.getResponse();

		String title = StringUtils.format("{}.{}", this.page.getTitle(), this.mp3Url.getAudioFormat());
		String header = req.getHeader("user-agent");
		if (header == null) {
			header = "";
		}

		header = header.toLowerCase();
		String filename = title;
		if (header.indexOf("msie") >= 0) {
			filename = URLUtils.encodeURIComponent(filename);
		} else {
			filename = new String(title.getBytes(AppEnvironment.charsetName), "ISO8859_1");
		}

		RandomAccessFile fileIn = new RandomAccessFile(file, "r");
		resp.addHeader("Content-Disposition", StringUtils.format("attachment; filename=\"{}\"", filename));
		resp.setContentType("audio/mpeg");
		
		long start = 0;
		long length = fileIn.length();
		long end = length - 1;
		resp.setContentLength((int)length);

		// bytes 0-11006012/11006013
		String range = req.getHeader("Range");
		if (range != null) {
			range = range.substring("bytes=".length());
			int index = range.indexOf('-');
			if (index >= 0) {
				String value = range.substring(0, index);
				if (!"".equals(value)) {
					start = Long.parseLong(value);
					fileIn.skipBytes((int) start);
				}
				value = range.substring(index + 1);
				if (!"".equals(value)) {
					end = Long.parseLong(value);
				}
			}
			resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
		} else {
			resp.setStatus(HttpServletResponse.SC_OK);
		}
		String contentRange = new StringBuilder("bytes ").append(start).append("-").append(end).append("/")
				.append(length).toString();
		resp.setHeader("Content-Range", contentRange);
		

		long readed = 0;
		long total = end - start + 1;
		ServletOutputStream sos = resp.getOutputStream();
		try {
			byte[] buffer = new byte[8192];
			while (readed < total) {
				int len = fileIn.read(buffer, 0, buffer.length);
				if (len <= 0) {
					break;
				}
				sos.write(buffer, 0, len);
				readed += len;
			}
		} finally {
			fileIn.close();
			sos.close();
		}
		
		return end >= length - 1;
	}
}